﻿#light

// Author: amr 8/16/08

// Original discussion:
// http://cs.hubfs.net/forums/thread/7877.aspx

#r "FSharp.PowerPack.dll"

open System.Drawing
open System.Windows.Forms
open Microsoft.FSharp.Math

let max_iter = 100;
let width, height = 700,600
let xmin, xmax = -2.0, 1.0
let ymin, ymax = -2.0, 2.0

let color_map = seq [ (0, Color.Black); (3, Color.Red); (6, Color.Blue); (10, Color.Chartreuse);
                      (20, Color.Magenta); (50, Color.DarkTurquoise); (100, Color.White) ]
                |> Seq.pairwise |> Seq.cache

let bitmap = new Bitmap( width, height, Imaging.PixelFormat.Format24bppRgb )
let form = new Form(
            Text = "F# Mandelbrot",
            Size = bitmap.Size)
            
let pic_box = new PictureBox(
                BorderStyle = BorderStyle.Fixed3D,
                Image = bitmap,
                Size = bitmap.Size,
                Dock = DockStyle.Fill,
                SizeMode = PictureBoxSizeMode.StretchImage)
form.Controls.Add( pic_box )

let mandelbrot c =
    let rec curse iter (z: complex) =
        if (iter = max_iter) || (z.Magnitude > 2.0) then
            iter
        else
            curse (iter + 1) (z*z + c)
    curse 0 c

let inline map (x1min, x1max) (x2min, x2max) =
    let ratio = (x2max - x2min) / (x1max - x1min)
    fun value ->
        (value - x1min) * ratio + x2min
        
let pick_color n =
        color_map
        |> Seq.find (fun ((a, _), (b, _)) -> (a <= n) && (n <= b))
        |> (fun ((a, c1), (b, c2)) ->
                let f (c, d) = map (a, b) (int c, int d) n
                Color.FromArgb( f (c1.R, c2.R),
                                f (c1.G, c2.G),
                                f (c1.B, c2.B) ))

let mapx = float >> map (0.0, float width) (xmin, xmax)
let mapy = float >> map (0.0, float height) (ymin, ymax)

for x = 0 to width - 1 do
    for y = 0 to height - 1 do
        bitmap.SetPixel( x, y, Complex.Create(mapx x, mapy y) |> mandelbrot |> pick_color )

#if INTERACTIVE
form.Show()
#else
Application.Run(form)
#endif 
